﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Management;
using System.Security.Cryptography;
using System.Text;

namespace SuppKids.Core.Security
{
	public static class ClientMachineManager
	{
		// ReSharper disable ConvertToConstant.Local
		private static readonly string wmiNamespace = "root\\CIMV2";
		private static readonly string baseBoardQueryFormat = "SELECT {0} FROM Win32_BaseBoard";
		private static readonly string baseBoardParameter = "SerialNumber";
		private static readonly string processorQueryFormat = "SELECT {0} FROM Win32_Processor";
		private static readonly string processorParameter = "ProcessorId";
		private static readonly string csProductQueryFormat = "SELECT {0} FROM Win32_ComputerSystemProduct";
		private static readonly string uuidParameter = "UUID";
	    // ReSharper restore ConvertToConstant.Local

		public static string CMID
		{
		    get
		    {
		        return GetCmidString(new MD5CryptoServiceProvider());
		    }
		}

	    private static string GetCmidString(HashAlgorithm hashAlgorithm)
		{
			var hashValue = hashAlgorithm.ComputeHash(Encoding.Unicode.GetBytes(GetParametersString()));

			var resultCmid = new StringBuilder();
			foreach (byte b in hashValue)
			{
				resultCmid.Append(string.Format(CultureInfo.InvariantCulture, "{0:x2}", b));
			}

			return resultCmid.ToString();
		}

		private static string GetParametersString()
		{
			return string.Concat(GetMotherboardId(), GetProcessorsIDs(), GetUuid());
		}

		private static string GetMotherboardId()
		{
			var result = GetParameter(baseBoardQueryFormat, baseBoardParameter);

			if (string.IsNullOrEmpty(result))
			{
				throw new Exception("Motherboard ID can't be obtained.");
			}

			return result;
		}

		private static string GetProcessorsIDs()
		{
			return GetParameter(processorQueryFormat, processorParameter);
		}

		private static string GetUuid()
		{
			var result = GetParameter(csProductQueryFormat, uuidParameter);

			if (string.IsNullOrEmpty(result))
			{
				throw new Exception("UUID can't be obtained.");
			}

			return result;
		}

	    private static string GetParameter(string query, string parameterName)
		{
			var searcher = new ManagementObjectSearcher(wmiNamespace, string.Format(CultureInfo.InvariantCulture, query, parameterName));

			var parameters = new List<string>();
			// ReSharper disable LoopCanBeConvertedToQuery
			foreach (ManagementObject managementObject in searcher.Get())
			// ReSharper restore LoopCanBeConvertedToQuery
			{
				parameters.Add(managementObject[parameterName].ToString());
			}

			var result = new string[parameters.Count];
			for (int i = 0; i < parameters.Count; i++)
			{
				result[i] = parameters[i];
			}

			return string.Concat(result);
		}
	}
}